/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id$
 */
package wx.xml.xalan.xalan.templates;

import java.util.Vector;

import javax.xml.transform.TransformerException;

/**
 * Represents a stylesheet that has methods that resolve includes and
 * imports.  It has methods on it that
 * return "composed" properties, which mean that:
 * <ol>
 * <li>Properties that are aggregates, like OutputProperties, will
 * be composed of properties declared in this stylsheet and all
 * included stylesheets.</li>
 * <li>Properties that aren't found, will be searched for first in
 * the includes, and, if none are located, will be searched for in
 * the imports.</li>
 * <li>Properties in that are not atomic on a stylesheet will
 * have the form getXXXComposed. Some properties, like version and id,
 * are not inherited, and so won't have getXXXComposed methods.</li>
 * </ol>
 * <p>In some cases getXXXComposed methods may calculate the composed
 * values dynamically, while in other cases they may store the composed
 * values.</p>
 */
public class StylesheetComposed extends Stylesheet {
    static final long serialVersionUID = -3444072247410233923L;
    /**
     * Order in import chain.
     *
     * @serial
     */
    private int m_importNumber = -1;
    /**
     * The precedence of this stylesheet in the global import list.
     * The lowest precedence stylesheet is 0.  A higher
     * number has a higher precedence.
     *
     * @serial
     */
    private int m_importCountComposed;
    /* The count of imports composed for this stylesheet */
    private int m_endImportCountComposed;
    /**
     * The combined list of includes.
     *
     * @serial
     */
    private transient Vector m_includesComposed;

    /**
     * Uses an XSL stylesheet document.
     *
     * @param parent The including or importing stylesheet.
     */
    public StylesheetComposed(Stylesheet parent) {
        super(parent);
    }

    /**
     * Tell if this can be cast to a StylesheetComposed, meaning, you
     * can ask questions from getXXXComposed functions.
     *
     * @return True since this is a StylesheetComposed
     */
    public boolean isAggregatedType() {
        return true;
    }

    /**
     * Adds all recomposable values for this precedence level into the recomposableElements Vector
     * that was passed in as the first parameter.  All elements added to the
     * recomposableElements vector should extend ElemTemplateElement.
     *
     * @param recomposableElements a Vector of ElemTemplateElement objects that we will add all of
     *                             our recomposable objects to.
     */
    public void recompose(Vector recomposableElements) throws TransformerException {

        //recomposeImports();         // Calculate the number of this import.
        //recomposeIncludes(this);    // Build the global include list for this stylesheet.

        // Now add in all of the recomposable elements at this precedence level

        int n = getIncludeCountComposed();

        for (int i = -1; i < n; i++) {
            Stylesheet included = getIncludeComposed(i);

            // Add in the output elements

            int s = included.getOutputCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getOutput(j));
            }

            // Next, add in the attribute-set elements

            s = included.getAttributeSetCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getAttributeSet(j));
            }

            // Now the decimal-formats

            s = included.getDecimalFormatCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getDecimalFormat(j));
            }

            // Now the keys

            s = included.getKeyCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getKey(j));
            }

            // And the namespace aliases

            s = included.getNamespaceAliasCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getNamespaceAlias(j));
            }

            // Next comes the templates

            s = included.getTemplateCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getTemplate(j));
            }

            // Then, the variables

            s = included.getVariableOrParamCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getVariableOrParam(j));
            }

            // And lastly the whitespace preserving and stripping elements

            s = included.getStripSpaceCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getStripSpace(j));
            }

            s = included.getPreserveSpaceCount();
            for (int j = 0; j < s; j++) {
                recomposableElements.addElement(included.getPreserveSpace(j));
            }
        }
    }

    /**
     * Recalculate the precedence of this stylesheet in the global
     * import list.  The lowest precedence stylesheet is 0.  A higher
     * number has a higher precedence.
     */
    void recomposeImports() {

        m_importNumber = getStylesheetRoot().getImportNumber(this);

        StylesheetRoot root              = getStylesheetRoot();
        int            globalImportCount = root.getGlobalImportCount();

        m_importCountComposed = (globalImportCount - m_importNumber) - 1;

        // Now get the count of composed imports from this stylesheet's imports
        int count = getImportCount();
        if (count > 0) {
            m_endImportCountComposed += count;
            while (count > 0)
                m_endImportCountComposed += this.getImport(--count).getEndImportCountComposed();
        }

        // Now get the count of composed imports from this stylesheet's
        // composed includes.
        count = getIncludeCountComposed();
        while (count > 0) {
            int imports = getIncludeComposed(--count).getImportCount();
            m_endImportCountComposed += imports;
            while (imports > 0)
                m_endImportCountComposed += getIncludeComposed(count).getImport(--imports).getEndImportCountComposed();

        }
    }

    /**
     * Get a stylesheet from the "import" list.
     *
     * @param i Index of stylesheet in import list
     * @return The stylesheet at the given index
     * @throws ArrayIndexOutOfBoundsException
     * @see <a href="http://www.w3.org/TR/xslt#import">import in XSLT Specification</a>
     */
    public StylesheetComposed getImportComposed(int i)
        throws ArrayIndexOutOfBoundsException {

        StylesheetRoot root = getStylesheetRoot();

        // Get the stylesheet that is offset past this stylesheet.
        // Thus, if the index of this stylesheet is 3, an argument
        // to getImportComposed of 0 will return the 4th stylesheet
        // in the global import list.
        return root.getGlobalImport(1 + m_importNumber + i);
    }

    /**
     * Get the precedence of this stylesheet in the global import list.
     * The lowest precedence is 0.  A higher number has a higher precedence.
     *
     * @return the precedence of this stylesheet in the global import list.
     * @see <a href="http://www.w3.org/TR/xslt#import">import in XSLT Specification</a>
     */
    public int getImportCountComposed() {
        return m_importCountComposed;
    }

    /**
     * Get the number of import in this stylesheet's composed list.
     *
     * @return the number of imports in this stylesheet's composed list.
     */
    public int getEndImportCountComposed() {
        return m_endImportCountComposed;
    }

    /**
     * Recompose the value of the composed include list.  Builds a composite
     * list of all stylesheets included by this stylesheet to any depth.
     *
     * @param including Stylesheet to recompose
     */
    void recomposeIncludes(Stylesheet including) {

        int n = including.getIncludeCount();

        if (n > 0) {
            if (null == m_includesComposed)
                m_includesComposed = new Vector();

            for (int i = 0; i < n; i++) {
                Stylesheet included = including.getInclude(i);
                m_includesComposed.addElement(included);
                recomposeIncludes(included);
            }
        }
    }

    /**
     * Get an "xsl:include" property.
     *
     * @param i Index of stylesheet in "include" list
     * @return The stylesheet at the given index in the "include" list
     * @throws ArrayIndexOutOfBoundsException
     * @see <a href="http://www.w3.org/TR/xslt#include">include in XSLT Specification</a>
     */
    public Stylesheet getIncludeComposed(int i)
        throws ArrayIndexOutOfBoundsException {

        if (-1 == i)
            return this;

        if (null == m_includesComposed)
            throw new ArrayIndexOutOfBoundsException();

        return (Stylesheet) m_includesComposed.elementAt(i);
    }

    /**
     * Get the number of included stylesheets.
     *
     * @return the number of included stylesheets.
     * @see <a href="http://www.w3.org/TR/xslt#import">import in XSLT Specification</a>
     */
    public int getIncludeCountComposed() {
        return (null != m_includesComposed) ? m_includesComposed.size() : 0;
    }

    /**
     * For compilation support, we need the option of overwriting
     * (rather than appending to) previous composition.
     * We could phase out the old API in favor of this one, but I'm
     * holding off until we've made up our minds about compilation.
     * ADDED 9/5/2000 to support compilation experiment.
     * NOTE: GLP 29-Nov-00 I've left this method in so that CompilingStylesheetHandler will compile.  However,
     * I'm not sure why it's needed or what it does and I've commented out the body.
     *
     * @param flushFirst Flag indicating the option of overwriting
     *                   (rather than appending to) previous composition.
     * @throws TransformerException
     * @see <a href="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
     */
    public void recomposeTemplates(boolean flushFirst) throws TransformerException {
/***************************************  KEEP METHOD IN FOR COMPILATION
 if (flushFirst)
 m_templateList = new TemplateList(this);

 recomposeTemplates();
 *****************************************/
    }
}
